/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#version 460  core

uniform sampler2D exitColorTexture;
uniform sampler2D exitDepthTexture;
uniform sampler2D mainDepthTexture;

uniform vec3 cameraPosInRaycaster;
uniform vec2 windowSize;

uniform int rayCastSteps;

; // preprocessor add semicolon to isolate error messages
#line 1 1 // C:\os\clean\OpenSpace-0.16.0\shaders\blending.glsl
/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef _BLENDING_GLSL_
#define _BLENDING_GLSL_

/**
 * Blend in src behind dst using normal blending
 * dst is premultiplied
 * src is expressed in straight RGBA
 */
void normalBlend(inout vec4 dst, vec4 src) {
    dst.rgb = dst.rgb + (1.f - dst.a) * src.a * src.rgb;
    dst.a = dst.a + (1.f - dst.a) * src.a;
}

/**
 * Blend in src behind dst using additive blending
 * dst is premultiplied
 * src is expressed in straight RGBA
 */
void additiveBlend(inout vec4 dst, vec4 src) {
    dst.rgb = dst.rgb + (1.f - dst.a) * src.a * src.rgb;//    dst.rgb = dst.rgb + src.a * src.rgb;
    //dst.a = dst.a + src.a;
}


/**
 * Blend in src behind dst using normal blending
 * dst is premultiplied
 * src is expressed in straight RGBA
 * stepSize = 0: alpha becomes 0
 * stepSize = 1: alpha becomes src.a
 */
void normalBlendStep(inout vec4 dst, vec4 src, float stepSize) {
    src.a = 1.f - pow(1.f - src.a, stepSize);
    normalBlend(dst, src);
}

/**
 * Blend in src behind dst using addivtive blending
 * dst is premultiplied
 * src is expressed in straight RGBA
 * stepSize = 0: alpha becomes 0
 * stepSize = 1: alpha becomes src.a
 */
void additiveBlendStep(inout vec4 dst, vec4 src, float stepSize) {
    src.a = 1.0 - pow(1.0 - src.a, stepSize);
    additiveBlend(dst, src);
}

/**
 * Blend in src behind dst
 * dst is premultiplied
 * src is expressed in straight RGBA
 */
void blend(inout vec4 dst, vec4 src) {
    dst.rgb = dst.rgb + (1.f - dst.a) * src.a * src.rgb;
    dst.a = dst.a + (1.f - dst.a) * src.a;
}

/**
 * Blend in src behind dst
 * dst is premultiplied
 * src is expressed in straight RGBA
 * stepSize = 0: alpha becomes 0
 * stepSize = 1: alpha becomes src.a
 */
void blendStep(inout vec4 dst, vec4 src, float stepSize) {
    src.a = 1.0 - pow(1.f - src.a, stepSize);
    blend(dst, src);
}

#endif // _BLENDING_GLSL_
; // preprocessor add semicolon to isolate error messages
#line 37 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag
; // preprocessor add semicolon to isolate error messages
#line 1 2 // C:\os\clean\OpenSpace-0.16.0\shaders\rand.glsl
/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef _RAND_GLSL_
#define _RAND_GLSL_

/**
 * Return a random number between 0 and 1, based on a vec2
 */
float rand(vec2 co){
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

#endif
; // preprocessor add semicolon to isolate error messages
#line 38 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag
; // preprocessor add semicolon to isolate error messages
#line 1 3 // C:\os\clean\OpenSpace-0.16.0\shaders\floatoperations.glsl
/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef _FLOATOPERATIONS_GLSL_
#define _FLOATOPERATIONS_GLSL_

/**
 * Convert a positive floating point distance [0, 10^27]
 * (size of observable universe)
 * to a float in the range [-1, 1], suitable for depth buffer storage.
 * Note: This needs to be a monotonic function, so that the value can
 * still be used for depth comparison.
 */
float normalizeFloat(float inpt) {
    if (inpt > 1.0) {
        return inpt / pow(10, 30);
    } else {
        return inpt - 1.0;
    }
}

float denormalizeFloat(float inpt) {
    if (inpt < 0.0) {
        return inpt + 1.0;
    } else {
        return inpt * pow(10, 30);
    }
}

/**
 * Compute the length of a vector.
 * Supporting huge vectors, where the square of any of the components is too large to be
 * represented as a float.
 */
float safeLength(vec4 v) {
    float m = max(max(max(abs(v.x), abs(v.y)), abs(v.z)), abs(v.w));
    if (m > 0.f) {
        return length(v / m) * m;
    } else {
        return 0.f;
    }
}

float safeLength(vec3 v) {
    float m = max(max(abs(v.x), abs(v.y)), abs(v.z));
    if (m > 0.f) {
        return length(v / m) * m;
    } else {
        return 0.f;
    }
}

float safeLength(vec2 v) {
    float m = max(abs(v.x), abs(v.y));
    if (m > 0.f) {
        return length(v / m) * m;
    } else {
        return 0.f;
    }
}

/**
 * Normalize a vector
 * Supporting huge vectors, where the square of any of the components is too large to be
 * represent as a float.
 */
vec3 safeNormalize(vec3 v) {
    float m = max(max(abs(v.x), abs(v.y)), abs(v.z));
    return normalize(v / m);
}

#endif // _FLOATOPERATIONS_GLSL_
; // preprocessor add semicolon to isolate error messages
#line 39 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag

//# Empty for loop
//# Terminated loop over helperPaths
; // preprocessor add semicolon to isolate error messages
#line 43 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag

; // preprocessor add semicolon to isolate error messages
#line 1 4 // C:\os\clean\OpenSpace-0.16.0\modules\galaxy\shaders\galaxyraycast.glsl
/*****************************************************************************************
*                                                                                       *
* OpenSpace                                                                             *
*                                                                                       *
* Copyright (c) 2014-2020                                                               *
*                                                                                       *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify,    *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
* permit persons to whom the Software is furnished to do so, subject to the following   *
* conditions:                                                                           *
*                                                                                       *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software.                                              *
*                                                                                       *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
****************************************************************************************/

uniform float maxStepSize0 = 0.1;
uniform vec3 aspect0 = vec3(1.0);
uniform float opacityCoefficient0 = 1.0;
uniform float absorptionMultiply0 = 50.0;
uniform float emissionMultiply0 = 1500.0;
uniform sampler3D galaxyTexture0;

void sample0(
  vec3 samplePos,
  vec3 dir,
  inout vec3 accumulatedColor,
  inout vec3 accumulatedAlpha,
  inout float stepSize
  ) {
    vec3 aspect = aspect0;
    stepSize = maxStepSize0 / length(dir / aspect);

    //Early ray termination on black parts of the data
    vec3 normalizedPos = samplePos * 2.f - 1.f;
    if (normalizedPos.x * normalizedPos.x + normalizedPos.y * normalizedPos.y > 0.7) {
        return;
    }

    vec4 sampledColor = texture(galaxyTexture0, samplePos.xyz);

    // Source textures currently are square-rooted to avoid dithering in the shadows.
    // So square them back
    sampledColor = sampledColor*sampledColor;

    // Fudge for the dust "spreading"
    sampledColor.a = clamp(sampledColor.a, 0.f, 1.f);
    sampledColor.a = pow(sampledColor.a, 0.7f);

    // Absorption probability
    float scaledDensity = sampledColor.a * stepSize * absorptionMultiply0;
    vec3 alphaTint = vec3(0.3f, 0.54f, 0.85f);
    vec3 absorption = alphaTint * scaledDensity;

    // Extinction
    vec3 extinction = exp(-absorption);
    accumulatedColor.rgb *= extinction;

    // Emission
    accumulatedColor.rgb +=
        sampledColor.rgb * stepSize * emissionMultiply0 * opacityCoefficient0;

    vec3 oneMinusFrontAlpha = vec3(1.f) - accumulatedAlpha;
    accumulatedAlpha += oneMinusFrontAlpha * sampledColor.rgb  * opacityCoefficient0;
  }

  float stepSize0(vec3 samplePos, vec3 dir) {
    return maxStepSize0 * length(dir * 1.f / aspect0);
  }
; // preprocessor add semicolon to isolate error messages
#line 45 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag

out vec4 finalColor;

#define ALPHA_LIMIT 0.99

; // preprocessor add semicolon to isolate error messages
#line 1 5 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\inside.glsl
/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014-2020                                                               *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

void getEntry(inout vec3 entryPos, inout float entryDepth) {
    entryPos = cameraPosInRaycaster;
    entryDepth = 0;
}
; // preprocessor add semicolon to isolate error messages
#line 51 0 // C:\os\clean\OpenSpace-0.16.0\shaders\framebuffer\raycastframebuffer.frag

void main() {
    vec2 texCoord = vec2(gl_FragCoord.xy / windowSize);

    // Boundary position in view space
    vec4 exitColorTexture = texture(exitColorTexture, texCoord);

    // If we don't have an exit, discard the ray
    if (exitColorTexture.a < 1.f || exitColorTexture.rgb == vec3(0.f)) {
        discard;
    }

    // Fetch exit point from texture
    vec3 exitPos = exitColorTexture.rgb;
    float exitDepth =  denormalizeFloat(texture(exitDepthTexture, texCoord).x);

    float jitterFactor = 0.5f + 0.5f * rand(gl_FragCoord.xy); // should be between 0.5 and 1.0

    vec3 entryPos;
    float entryDepth;
    getEntry(entryPos, entryDepth);
    // If we don't have an entry, discard the ray
    if (entryPos == vec3(0.f)) {
        discard;
    }

    vec3 position = entryPos;
    vec3 diff = exitPos - entryPos;

    vec3 direction = normalize(diff);
    float raycastDepth = length(diff);

    float geoDepth = denormalizeFloat((texture(mainDepthTexture, texCoord).x));
    float geoRatio = clamp((geoDepth - entryDepth) / (exitDepth - entryDepth), 0.f, 1.f);
    raycastDepth = geoRatio * raycastDepth;

    float currentDepth = 0.f;
    float nextStepSize = stepSize0(position, direction);
    float currentStepSize;
    float previousJitterDistance = 0.f;

    int nSteps = 0;

    int sampleIndex = 0;
    float opacityDecay = 1.f;

    vec3 accumulatedColor = vec3(0.f);
    vec3 accumulatedAlpha = vec3(0.f);


    for (nSteps = 0;
        (accumulatedAlpha.r < ALPHA_LIMIT || accumulatedAlpha.g < ALPHA_LIMIT ||
         accumulatedAlpha.b < ALPHA_LIMIT) && nSteps < rayCastSteps;
         ++nSteps)
    {
        if (nextStepSize < raycastDepth / 10000000000.f) {
            break;
        }

        currentStepSize = nextStepSize;
        currentDepth += currentStepSize;

        float jitteredStepSize = currentStepSize * jitterFactor;
        vec3 jitteredPosition = position + direction * jitteredStepSize;
        position += direction * currentStepSize;

        sample0(jitteredPosition, direction, accumulatedColor, accumulatedAlpha, nextStepSize);
        float sampleDistance = jitteredStepSize + previousJitterDistance;

        previousJitterDistance = currentStepSize - jitteredStepSize;

        float maxStepSize = raycastDepth - currentDepth;
        nextStepSize = min(nextStepSize, maxStepSize);
    }

    finalColor = vec4(accumulatedColor, (accumulatedAlpha.r + accumulatedAlpha.g + accumulatedAlpha.b) / 3.f);

    finalColor.rgb /= finalColor.a ;

    gl_FragDepth = normalizeFloat(entryDepth);
}
